
bl_info = {
    "name": "Export OSSL Animation File",
    "author": "Tom Ernst",
    "version": (1, 0, 0),
    "blender": (2, 93, 0),
    "location": "Topbar > OSSL Menu > Export OSSL Animation File",
    "description": "Export OSSL Animation File from Armature Object",
    "warning": "",
    "doc_url": "https://rowlplay.net/blender/animexp.txt",
    "category": "Import-Export",
}

import bpy
from bpy.props import *
from bpy_extras.io_utils import ExportHelper

from ossl._types.Animation import Animation
from ossl.formats.format_ANIM import Format_ANIM

from mathutils import Matrix

def update_times(self, context):
    frames = range(self.frame_first, self.frame_last + 1)
    self["duration_"] = len(frames) / self.fps
    self["loop_start_"] = self.loop_frame_first / self.fps
    self["loop_end_"] = (self.loop_frame_first + self.loop_frame_count) / self.fps
    
def get_duration(self): return self.duration_
def get_loop_start(self): return self.loop_start_
def get_loop_end(self): return self.loop_end_

class OSSL_OT_Animation_export_ANIM(bpy.types.Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_label = "OSSL Menu Animation Export ANIM"
    bl_idname = "ossl.export_animation_anim"

    filename_ext = ".anim"
    
    priority: IntProperty(
        default = 5, min = 1, max = 6,
        name = "Base Priority",
        description = "Base Animation Priority"
    )

    fps: FloatProperty(
        default=24, step=100,
        name = "FPS",
        description = "Frames per Second",
        update = update_times
    )
    
    frame_first: IntProperty(
        default=0,
        name="First Frame",
        description = "Index of first Frame to be exported",
        update = update_times
    )
    
    frame_last: IntProperty(
        default=0,
        name="Last Frame",
        description = "Index of last Frame to be exported",
        update = update_times
    )
    
    duration: FloatProperty(
        name = "Duration (sec.)",precision=3,
        description = "Duration of Animation in Seconds",
        get = get_duration 
    )
    duration_: FloatProperty(options={'HIDDEN'})
    
    loop_frame_first: IntProperty(
        default=0,
        name="Loop Frame Start",
        description = "Index of first Loop Frame",
        update = update_times
    )    
    loop_start: FloatProperty(name="Loop Start (sec.)", precision=3, description="Start Time of Loop in Seconds", get=get_loop_start)
    loop_start_: FloatProperty(options={"HIDDEN"})

    loop_frame_count: IntProperty(
        default=0,
        name="Loop Frame Count",
        description = "Count of Loop Frames",
        update = update_times
    )
    loop_end: FloatProperty(name="Loop End (sec.)", precision=3, description="End Time of Loop in Seconds", get=get_loop_end)
    loop_end_: FloatProperty(options={"HIDDEN"})

    ease_in_duration: FloatProperty(
        default = 0.3,
        name = "Ease In Duration",
        description = "Ease-In Duration in Seconds"
    )

    ease_out_duration: FloatProperty(
        default = 0.3,
        name = "Ease Out Duration",
        description = "Ease-Out Duration in Seconds"
    )

    hand_pose: EnumProperty(
        default = "OPT_01",
        name = "Hand Pose",
        description = "Hand Pose while Animation is running",
        items = (
            ("OPT_00", "Spread", "Fingers are spread"),
            ("OPT_01", "Relaxed", "Hand is relaxed"),
            ("OPT_02", "pointing", "Avatar points sth."),
            ("OPT_03", "Fist", "Avatar makes Fists"),
            ("OPT_04", "Left relaxed", "Left Hand is relaxed"),
            ("OPT_05", "Left pointing", "Avatar point sth. with left Hand"),
            ("OPT_06", "Left Fist", "Avatar makes a left Fist"),
            ("OPT_07", "Right relaxed", "Right Hand is relaxed"),
            ("OPT_08", "Right pointing", "Avatar point sth. with right Hand"),
            ("OPT_09", "Right Fist", "Avatar makes a right Fist"),
            ("OPT_10", "Right Salute", "Salute Pose"),
            ("OPT_11", "typing", "Fingers move as typing"),
            ("OPT_12", "Right Peace Sign", "Avatar makes Peace Pose with right Hand"),
            ("OPT_13", "Right Palm", "Right Hand is held flat"),
        )
    )

    filter_glob: StringProperty(
        default="*.anim",
        options={'HIDDEN'},
        maxlen=255,  # Max internal buffer length, longer would be clamped.
    )
        
    @classmethod
    def poll(cls, context):
        return cls.getContextAction(context) != None
    
    @classmethod
    def getContextAction(cls, context):
        obj = context.object
        if not(obj): return None
        if not(obj.type == 'ARMATURE'): return None
        if not(obj.animation_data): return None
        if not(obj.animation_data.action): return None
        return obj.animation_data.action
    
    def invoke(self, context, event):
        action = self.getContextAction(context)
        armature = context.object
        adj_mat = armature.data.bones["mPelvis"].matrix.inverted().to_4x4()
        print("\n\nanim adj_mat before:\n", adj_mat)
        #adj_mat = Matrix(((0,0,1),(1,0,0),(0,1,0))).to_4x4() @ adj_mat
        print("anim adj_mat after:\n", adj_mat)
        self.anim = Animation(context.scene, armature, action, adj_mat).prepare_for_export()
        print("\n\n>>>>>>>>>>>>>", self.anim.frames, "<<<<<<<<<<<<<<<<<\n")
        self.frame_first = self.anim.frames.start
        self.frame_last = self.anim.frames.stop - 1
        markers = context.scene.timeline_markers
        if "loop_first" in markers: self.loop_frame_first = markers["loop_first"].frame
        if "loop_last" in markers: self.loop_frame_count = markers["loop_last"].frame - self.loop_frame_first + 1
        #print(dir(self.priority))
        return super().invoke(context, event)

    def execute(self, context):
        keywords = self.as_keywords(
            ignore=(
                "filter_glob",
                "check_existing",
            )
        )
        fps = self.fps
        frames = range(0, self.frame_last - self.frame_first + 1)
        duration = len(frames) / fps
        ls = self.loop_frame_first - self.frame_first
        le = ls + self.loop_frame_count
        loop = range(ls, le)
        hand_pose = int(self.hand_pose[4:6])
        ease_durations = (round(self.ease_in_duration, 6), round(self.ease_out_duration, 6))
#        fps = 6
#        frames = range(0, 97)
#        loop = range(12, 84)
        Format_ANIM(self.anim, self.priority, fps, frames, loop, hand_pose, ease_durations).export(self.filepath)
        print("Export ANIM called")
        return { 'FINISHED' }

def OSSL_operator_Animation_export_ANIM(self, comtext):
    self.layout.operator(OSSL_OT_Animation_export_ANIM.bl_idname, text=".anim", icon='ARMATURE_DATA')

import ossl.util as util

addon_keymaps = []

def register():
    print("registering: OSSL Type Animation Export ANIM")
    bpy.utils.register_class(OSSL_OT_Animation_export_ANIM)
    bpy.types.OSSL_MT_Animation_export.append(OSSL_operator_Animation_export_ANIM)
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = kc.keymaps.new(name="Screen",region_type='WINDOW')
        kmi = km.keymap_items.new("ossl.export_animation_anim", type="X", value="PRESS", shift=True, alt=True)
        addon_keymaps.append((km, kmi))
    print("registered: OSSL Type Animation Export ANIM")

def unregister():
    print("unregistering: OSSL Type Animation Export ANIM")
    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()
    bpy.types.OSSL_MT_Animation_export.remove(OSSL_operator_Animation_export_ANIM)
    bpy.utils.unregister_class(OSSL_OT_Animation_export_ANIM)
    print("unregistered: OSSL Type Animation Export ANIM")

if __name__ == "__main__":
    import ossl.util as util
    util.reset_addon()
